#include "DataManager.hpp"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

string NumToString(int num) // Returns a string object for a given integer
{
	stringstream ss;
	ss << num;
	return ss.str();
}
string NumToString(float num) // Returns a string object for a given integer
{
	stringstream ss;
	ss << num;
	return ss.str();
}

void ParseData(int& pos, string& stored, unsigned char* data)
{
	while (data[pos] != '$') 
	{
		stored.push_back(data[pos]);
		++pos;
	}
	++pos;
}


void DataManager::ChangeUnit(int ID, const Unit& newUnit)
{
	if(ID > mUnits.size() - 1)
	{
		cout << "Invalid ID ( " << ID << " ) called in ChangeUnit" << endl;
		return;
	}

	mUnits[ID] = newUnit;
}
Unit DataManager::GetUnit(int ID)
{
	if(ID > mUnits.size() - 1 || ID < 0 || mUnits.size() == 0)
	{
		cout << "Invalid ID ( " << ID << " ) called in GetUnit" << endl;
		Unit retn = {0, 0, 0, 0, 0, 0, 0, 0};
		retn.notRealUnit = true;
		return retn;
	}

	return mUnits[ID];

}

int DataManager::AddUnit(Unit& newUnit)
{
	newUnit.notRealUnit = false;
	mUnits.push_back(newUnit);
	
	cout << "Created unit ( " << mUnits.size() - 1 << " ) with ( " << newUnit.x << " " << newUnit.y << " " << newUnit.xVel << " " << newUnit.yVel << " )" << endl;
	return mUnits.size() - 1;
}


int DataManager::AddUnit(unsigned char* data)
{
	string netData;
	// ID
	int ID = mUnits.size();
	
	Unit unt;
	unt.notRealUnit = false;

	int pos = 1;
	// get x
	netData.clear();
	ParseData(pos, netData, data);
	unt.x = atoi(netData.c_str());

	// get y
	netData.clear();
	ParseData(pos, netData, data);
	unt.y = atoi(netData.c_str());

	// get xVel
	netData.clear();
	ParseData(pos, netData, data);
	unt.xVel = atof(netData.c_str());

	// get yVel
	netData.clear();
	ParseData(pos, netData, data);
	unt.yVel = atof(netData.c_str());

	return (this->AddUnit(unt));
}

void DataManager::ChangeUnitLocation(unsigned char* data)
{
	string netData;

	int pos = 1;

	// get our unit ID
	ParseData(pos, netData, data);
	int unitID = atoi(netData.c_str());
	Unit unt = this->GetUnit(unitID);

	// change x
	netData.clear();
	ParseData(pos, netData, data);
	unt.x = atoi(netData.c_str());

	// change y
	netData.clear();
	ParseData(pos, netData, data);
	unt.y = atoi(netData.c_str());

	// change xVel
	netData.clear();
	ParseData(pos, netData, data);
	unt.xVel = atof(netData.c_str());

	// change yVel
	netData.clear();
	ParseData(pos, netData, data);
	unt.yVel = atof(netData.c_str());

	this->ChangeUnit(unitID, unt);
	//cout << "Changed unit ( " << unitID << " ) to ( " << unt.x << " " << unt.y << " " << unt.xVel << " " << unt.yVel << " )" << endl;
	//cout << "Message was: " << data << endl;
}

string DataManager::GetUnitLocation(unsigned char* data)
{

	string netData;
			

	// get our unit ID
	int pos = 1;
	ParseData(pos, netData, data);
	int unitID = atoi(netData.c_str());
	netData.append("$");

	Unit unt = this->GetUnit(unitID);

	if(unt.notRealUnit)
		return "invalidID";

	
	// x
	netData.append(NumToString(unt.x));
	netData.append("$");

	// y
	netData.append(NumToString(unt.y));
	netData.append("$");
	


	// xVel
	netData.append(NumToString(unt.xVel));
	netData.append("$");

	// yVel
	netData.append(NumToString(unt.yVel));
	netData.append("$");
	
	return netData;


}

string DataManager::GetUnitLocation(int ID)
{
	string netData;
			
	Unit unt = this->GetUnit(ID);

	if(unt.notRealUnit)
		return "invalidID";

	// id
	netData.append(NumToString(ID));
	netData.append("$");
	
	// x
	netData.append(NumToString(unt.x));
	netData.append("$");

	// y
	netData.append(NumToString(unt.y));
	netData.append("$");
	
	// xVel
	netData.append(NumToString(unt.xVel));
	netData.append("$");

	// yVel
	netData.append(NumToString(unt.yVel));
	netData.append("$");
	
	return netData;
}



void DataManager::SaveData(unsigned char* dataWithoutExtensions)
{
	string path;
	int pos = 1;
	ParseData(pos, path, dataWithoutExtensions);
	// create the "entities" file
	string entityPath = path.c_str();
	entityPath.append(".entities");
	ofstream file;
	file.open(entityPath.c_str());
	if(file.is_open())
	{
		file << mUnits.size() << "\n";
		for(int i = 0; i < mUnits.size(); ++i)
			file << mUnits[i].x << " " << mUnits[i].y << " " << mUnits[i].xVel << " " << mUnits[i].yVel << "\n";

		file.close();

		cout << "The server successfully saved " << path << endl;
	}
	else
		cout << "The server did not save" << path << endl;




}

void DataManager::LoadData(unsigned char* dataWithoutExtensions)
{

	string path;
	int pos = 1;
	ParseData(pos, path, dataWithoutExtensions);

	mUnits.resize(0);

	string entityPath = path.c_str();
	entityPath.append(".entities");
	ifstream file;
	file.open(entityPath.c_str());

	string line;
	if(file.is_open())
	{
		Unit unit;
		unit.notRealUnit = false;
		file.seekg(0);
		int totalEnt;
		file >> totalEnt;

		for(int i = 0; i < totalEnt; ++i)
			{
				file >> unit.x >> unit.y >> unit.xVel >> unit.yVel;
							
				this->AddUnit(unit);
				//mUnits.push_back(unit);
			}

		
		file.close();

		cout << "The server successfully loaded " << path << endl;
	}
	else
		cout << "The server did not load " << path << endl;
}